package org.mebusw.struts.davincicode;

import java.io.Serializable;
import java.util.ArrayList;

/**
 * @author j1shen
 * @see DavinciCard
 */
public class CardHand extends ArrayList<DavinciCard> implements Serializable {
	public CardHand() {

	}

	/**
	 * Insert a card into specific position.
	 * 
	 * @param card
	 *            the card to be inserted
	 * @param pos
	 *            the position to insert to
	 */
	public void insert(DavinciCard card, int pos) {
		this.add(pos, card);
	}

	/**
	 * Automatically insert a card with sorting.
	 * 
	 * @param card
	 *            the card to be inserted
	 */
	public void insertSort(DavinciCard card) {
		for (int i = 0; i < this.size() + 1; i++) {
			if (validatePos(card, i)) {
				insert(card, i);
				break;
			}
		}
	}

	/**
	 * Insert a card to the last position without sorting.
	 * 
	 * @param card
	 */
	public void insertLast(DavinciCard card) {
		this.add(this.size(), card);
	}

	/**
	 * Get the card in the last position.
	 * 
	 * @return The last card or null
	 */
	public DavinciCard getLast() {
		if (this.size() > 0)
			return this.get(this.size() - 1);
		else
			return null;
	}

	/**
	 * Validate whether a card can be insert into specific position. <br>
	 * <br>
	 * All cards should be sorted by ascending order, Black less than White if
	 * the same number, joker can be in any place.
	 * 
	 * @param card
	 *            the card to be inserted
	 * @param pos
	 *            the position to insert to
	 * @return true if the insertion is valid (but the card would not be
	 *         inserted)
	 */
	public boolean validatePos(DavinciCard card, int pos) {
		DavinciCard prev, succ;
		boolean result = false;

		if (pos < 0 || pos > this.size())
			return false;

		try {
			prev = this.get(pos - 1);
			if (prev.isJoker()) { // skip one joker
				prev = this.get(pos - 2);
				if (prev.isJoker()) // skip another joker
					prev = this.get(pos - 3);
			}
			if (card.getValue() == prev.getValue() && (prev.isBlack())
					|| card.getValue() > prev.getValue())
				result = true;
		} catch (IndexOutOfBoundsException e) {
			// reach to the head (after skipping any jokers)
			result = true;
		}

		try {
			succ = this.get(pos + 0);
			if (succ.isJoker()) { // skip one joker
				succ = this.get(pos + 1);
				if (succ.isJoker()) // skip another joker
					succ = this.get(pos + 2);
			}
			if (card.getValue() == succ.getValue() && !(succ.isBlack())
					|| card.getValue() < succ.getValue())
				result &= true;
			else
				result = false;
		} catch (IndexOutOfBoundsException e) {
			// reach to the tail (after skipping any jokers)
			result &= true;
		}

		return result;

	}

	public void reinsertSortLast() {
		DavinciCard card = this.getLast();
		this.remove(this.size() - 1);
		this.insertSort(card);

	}

	public int getStandingCardCount() {
		DavinciCard card;
		int sum = 0;
		for (int i = 0; i < this.size(); i++) {
			card = this.get(i);
			if (! card.isUncover())
				sum++;
		}
		return sum;
	}

}
